<template>
  <div>
    <div id="ui_top_panel" class="top_panel">
      <!-- 导航栏 -->
      <div class="navbar">
        <ul>
          <li class="dropdown"><a title="图像" class="drop_menu_item">任务 &#9662;</a>
            <div class="dropdown-content">
              <a title="从本地磁盘载入或添加图像" @click="getResource">载入/添加任务</a>
            </div>
          </li>
        </ul>
        <el-dialog
          v-dialogDrag
          title="选择任务"
          :visible.sync="centerDialogVisible"
          width="80%"
          :modal="false"
          center
        >
          <TaskMark></TaskMark>
        </el-dialog>
      </div>
      <div class="toolbar">
        <ul>
          <li>
            <toggle-button
              v-model="isVetical"
              :width="60"
              :height="30"
              :disabled="image_id_list.length===0"
              :sync="true"
              :labels="{checked: '纵向', unchecked: '横向'}"
              @change="changeVetical"
            />
          </li>
          <li id="toolbar_zoom_out" style="margin-left: 2em;" title="缩小" @click="zoom_out()">&minus;</li>
          <li id="toolbar_zoom_in" title="放大" @click="zoom_in()">&plus;</li>
          <!-- <li id="toolbar_zoom_reset" @click="reset_zoom_level()" title="重置视图">&equals;</li> -->
          <li id="reposition" title="图片复位" @click="reposition()">复位</li>
          <li id="save_temp_data" title="暂时保存标注" @click="save_data(1)">暂存标注</li>
          <li id="save_data" title="上传标注数据到服务器" @click="save_data(0)">上传标注</li>
        </ul>
      </div> <!-- endof #toolbar -->
      <input id="invisible_file_input" type="file" multiple name="files[]" style="display:none">
    </div> <!-- endof #top_panel -->
    <!-- 中部：包括左侧工具栏和图像显示区 左边框250 -->
    <div class="middle_panel">
      <div id="leftsidebar" class="leftSizeBar" style="height: 100%;">
        <div>
          <el-card class="cardClass">
            <div>
              <div slot="header" class="clearfix">
                <span>图片列表</span>
              </div>
              <div class="box">
                <div v-for="(img, index) in image_name_list" :key="index" @click="show_image(index)">
                  <el-button type="text" :class="{active: currentIndex === index}" style="padding:0;" :title = "img.imageName">
                    {{ "("+ (index+1)+ ")"}}.{{imageStatus[img.status]}}_{{ img.imageName}}
                  </el-button>
                </div>
              </div>
              <el-dialog
                title="提示"
                :append-to-body="true"
                :close-on-click-modal="false"
                :visible.sync="submitDialogVisible"
                width="30%"
                center
                @close = "cancel">
                <span>是否暂存/上传标注</span>
                <span slot="footer" class="dialog-footer">
                  <el-button @click="cancel">取 消</el-button>
                  <el-button type="primary" @click="submitstorecenter">暂存</el-button>
                  <el-button type="primary" @click="submit">上传</el-button>
                </span>
              </el-dialog>
            </div>
          </el-card>
        </div>
        <div id="leftAll" style="height: 100%" @contextmenu.prevent="onContextmenu0">
          <el-card class="box-card">
            <div id="leftTree" slot="header" style="height: 100%" class="clearfix">
              <span>目录树</span>
            </div>
            <div id="Tree" ref="treeRef" class="tree_box">
              <el-tree
                ref="vuetree"
                :data="node_data"
                node-key="id"
                highlight-current
                default-expand-all
                :expand-on-click-node="false"
              >
                <span
                  slot-scope="{ node, data }"
                  style="width: 100%"
                  class="custom-tree-node"
                  @contextmenu.stop.prevent="onContextmenu($event,node,data)"
                  @click="() => show_node(node, data)"
                >
                  <span :style="getDetectStyle(node.data.need_detect)">
                    {{ node.label }} {{node.data.label_idx}}
                  </span>
                </span>
              </el-tree>
            </div>
          </el-card>
        </div>
      </div> <!-- end of leftsidebar -->
      <!-- 主显示区：图像画布canvas -->
      <!--      <div id = "leftSidearHidden" display:none></div>-->
      <div id="display_area" v-loading="is_loading_current_image">
        <div id="canvas_panel" @mousewheel.prevent="handleWheel">
          <VueDragResize
            ref="vueDR"
            :is-resizable="false"
            :is-draggable="isDragActive&&image_id_list.length!==0"
            :w="1"
            :h="1"
            @dragging="onDragging"
          >
            <canvas id="image_canvas" class="mainSizeBar" :style="{cursor: 'pointer'}"/>
            <canvas id="region_canvas" class="mainSizeBar" :style="getStyle()"/>
          </VueDragResize>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import jasonVueExplorer from './explorer'
import {postMarkData1, getFiles, getBase64} from '../../api/commonService'
import VueDragResize from 'vue-drag-resize'
import TaskMark from '../minetask/index'
import { passJudge } from '@/api/task/taskcheck'

class ImageMetadata {
  constructor(fileref, filename, size, fileid, filestatus) {
    this.fileid = fileid  //图片在数据库中的id
    this.filename = filename
    this.filestatus = filestatus
    this.size = size
    this.isVetical = true
    this.fileref = fileref // image url or local file ref.图片的详细信息
    this.regions = [] // 区域
    this.base64_img_data = '' // image data stored as base 64
    this.node_tree = [] // 目录树
  }
}

class ImageRegion {
  constructor() {
    this.node_id = 0 // 记录其在目录树节点的id
    this.is_user_selected = false // 默认为不选中
    this.shape_attributes = new Map() // 存该区域的坐标
  }
}

export default {
  name: 'Marking',
  components: {
    jasonVueExplorer,
    VueDragResize,
    TaskMark
  },
  dicts: ['task_status','audit_status'],
  inject:['reload'],
  data() {
    return {
      current_label: '',
      current_need_detect: 1,
      hasModified: false, //是否修改过当前标注
      submitIndex:-1,
      index:0,
      submitDialogVisible:false,
      imageStatus: ['审核不通过','未完成','完成部分','等待审核','审核通过'], //0审核不通过/1未完成/2完成部分/3等待审核/4审核通过
      markTaskId: 0,  //当前任务id
      leftTree: '',
      leftAll: '',
      tree: '',
      isDialogOpen: false,
      isDragActive: false,
      // selectpath: 'D:\\',
      selectpath: '/home/fzuir/newspaper_data',
      // 远程文件管理需要的变量
      currentIndex: -1,
      centerDialogVisible: false,
      // rootPath: 'D:\\',
      rootPath: '/home/fzuir/newspaper_data',
      currentPath: '',
      pathStack: [],
      dataArr: [],
      selection: true,
      selectedArr: [],
      otherColumnArr: [
        {
          label: '时间',
          key: 'time'
        }
      ],
      seletedFileList: [],
      // imageDetailList:[], //存储被选中图片的所有信息 根据seletedFileList中的信息做扩展 base64 width height  size
      isVetical: true,
      nid: 0, // 目录树的id
      node_data: [],
      // current_node: {},
      current_parent_node: {},
      can_draw_region: false, // 是否能画图
      REGION_SHAPE: { // 标注区域的形状
        RECT: 'rect' // 矩形
      },
      REGION_EDGE_TOL: 5, // pixel，误差范围之内就算点击到框边缘
      REGION_CONTROL_POINT_SIZE: 2,
      REGION_POINT_RADIUS: 3,
      POLYGON_VERTEX_MATCH_TOL: 5,
      REGION_MIN_DIM: 3, // 如果画的框太小
      MOUSE_CLICK_TOL: 2, // 移动超过2px就算移动
      CANVAS_DEFAULT_ZOOM_LEVEL_INDEX: 3, // 指代1
      CANVAS_ZOOM_LEVELS: [0.25, 0.5, 0.75, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.5, 4, 4.5, 5], // 缩放的尺度

      THEME_REGION_BOUNDARY_WIDTH: 2,
      THEME_BOUNDARY_LINE_COLOR: '#1a1a1a',
      THEME_BOUNDARY_FILL_COLOR: '#ff0000',
      THEME_SEL_REGION_FILL_COLOR: '#a2a8a2',
      THEME_SEL_REGION_FILL_BOUNDARY_COLOR: '#000000',
      THEME_SEL_REGION_OPACITY: 0.5,
      THEME_CONTROL_POINT_COLOR: '#ff0000',

      img_metadata: {}, // 用来存已导入的每张图片的详细信息，包括上面标注的区域信息data structure to store loaded images metadata
      img_count: 0, // count of the loaded images
      canvas_regions: [], // 当前图片窗口中canvas的坐标 image regions spec. in canvas space
      canvas_scale: 1.0, // 原图缩小到canvas的倍数 current scale of canvas image

      image_id_list: [], // 保存已加载图片的id
      image_name_list: [], // 保存已加载图片的image_name
      image_path_list: [],
      image_id: '', // id of current image
      image_index: -1, // 当前正在浏览的图片索引index

      current_image_filename: '',
      current_image: '',
      current_image_width: 0,
      current_image_height: 0,

      // image canvas
      img_canvas: '',
      img_ctx: '',
      reg_canvas: '',
      reg_ctx: '',
      canvas_width: 0,
      canvas_height: 0,

      // canvas zoom
      canvas_zoom_level_index: 3, // 1.0
      canvas_scale_without_zoom: 1.0,

      // state of the application
      is_user_drawing_region: false,
      current_image_loaded: false, // 图片是否在加载中
      is_window_resized: false,
      is_user_resizing_region: false,
      is_user_moving_region: false,
      is_user_drawing_polygon: false,
      is_region_selected: false,
      is_all_region_selected: false,
      is_user_updating_attribute_name: false,
      is_user_updating_attribute_value: false,
      is_user_adding_attribute_name: false,
      is_canvas_zoomed: false,
      is_loading_current_image: false, // 是否正在加载图片(导入图片的时候会用)
      is_region_boundary_visible: true,

      // region
      current_shape: '',
      user_sel_region_id: -1,
      click_x0: 0,
      click_y0: 0,
      click_x1: 0,
      click_y1: 0,
      region_click_x: 0,
      region_click_y: 0,
      region_edge: [-1, -1],
      current_x: 0,
      current_y: 0,

      // UI html elements
      ui_top_panel: '',
      canvas_panel: '',

      BBOX_LINE_WIDTH: 4,
      BBOX_SELECTED_OPACITY: 0.3,
      BBOX_BOUNDARY_FILL_COLOR_ANNOTATED: '#f2f2f2',
      BBOX_BOUNDARY_FILL_COLOR_NEW: '#aaeeff',
      BBOX_BOUNDARY_LINE_COLOR: '#1a1a1a',
      BBOX_SELECTED_FILL_COLOR: '#ffffff',

      is_ctrl_pressed: false,
      remote_node_data: [], // 从后端获取的当前图片的node_data
      remote_is_vetical: true, // 从后端获取的当前图片的状态
      remote_regions: [], // 远程node中读出的region
      max_id: 0 // 当前图片远程目录树node的最大id
    }
  },

  activated() {
    console.log('activated')
    window.addEventListener('keyup', this.keyup)
    window.addEventListener('keydown', this.keydown)
    if (this.$store.state.taskmark.flag === true && this.$route.query.taskMarkId !== this.$store.state.taskmark.task_id) {
      console.log('清空')
      Object.assign(this.$data, this.$options.data.call(this))
      this.get_init()
      this.$store.commit('SET_MARK_FLAG_FALSE')
      this.$store.commit('SET_MARK_TASKID', this.$route.query.taskMarkId)
      // this.clear_reg_canvas()
    }
    this.getCheckedImage()
  },
  mounted() {
    // console.log(this.$store.state.marking.flag)
    this.get_init()
    // user clicks on the canvas
    this.reg_canvas.addEventListener('mousedown', this.mouse_down)
    // implements the following functionalities:
    //  - new region drawing (including polygon)
    //  - moving/resizing/select/unselect existing region
    this.reg_canvas.addEventListener('mouseup', this.mouse_up)

    this.reg_canvas.addEventListener('mousemove', this.mouse_move)

    this.reg_canvas.addEventListener('mouseover', this.mouse_over)
  },
  deactivated() {
    console.log('deactivated')
    window.removeEventListener('keydown', this.keydown)
    console.log('marking/marking.vue')
  },
  methods: {
    compare(obj1, obj2) {
      let s1 = obj1.status
      let s2 = obj2.status
      if(s1 < s2) return -1
      else if( s1 > s2) return 1
      else return 0
    },
    getCheckedImage() {
      this.onDragging({top: 0, left: 0})
      this.dataArr = []
      let imageList = this.$route.query.row  //任务中图片的信息
      this.markTaskId = this.$route.query.taskMarkId  //该任务的id

      for (const item of imageList) {
        // console.log(item)
        const data_item = {}
        data_item['key'] = item.imageId
        data_item['name'] = item.imageName
        data_item['filepath'] = item.iamgePath
        data_item['status'] = item.status  // 图片状态：0审核不通过/1未完成/2完成部分/3等待审核/4审核部分/5审核通过
        data_item['type'] = 'image'

        /*因为是标注，此时不拿json文件*/
        data_item['result_path'] = ''
        // data_item['result_path'] = result_path
        if (item.type === 'image') {
          data_item['height'] = item.height
          data_item['size'] = item.size
          data_item['width'] = item.width
          // data_item['base64'] = item.base64
        }
        this.seletedFileList.push(data_item)

      }
      // this.image_index=0
      // this.image_id = imageList[0].imageId
      // this.currentIndex=-1
      // this.image_index=-1
      // console.log('this.image_index',this.image_index)
      // console.log('this.currentIndex',this.currentIndex)
      this.store_remote_img_ref()
      // console.log('222222')
      // console.log('this.image_index',this.image_index)
      // console.log('this.currentIndex',this.currentIndex)
      window.addEventListener('keydown', this.keydown)
    },
    keydown(e) {
      if (e.which === 46 || e.which === 8) { // Del or Backspace
        if (!this.isDialogOpen) {
          // console.log('按下del')
          this.del_sel_regions()
          e.preventDefault() // 阻止默认事件，因为会导致搜索框不能删除文字，所以不阻止删除的冒泡时间
          return
        }
      }
      if (e.which === 37) { // 左移框
        if(this.is_region_selected){
          console.log('左移3px', this.user_sel_region_id)
          this.key_move(-3, 0)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }
      if (e.which === 38) { // 上移框
        if(this.is_region_selected){
          console.log('上移3px', this.user_sel_region_id)
          this.key_move(0, -3)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }
      if (e.which === 39) { // 右移框
        if(this.is_region_selected){
          console.log('右移3px', this.user_sel_region_id)
          this.key_move(3, 0)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }
      if (e.which === 40) { // 上移框
        if(this.is_region_selected){
          console.log('下移3px', this.user_sel_region_id)
          this.key_move(0, 3)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }

      // Ctrl + 快捷键
      if (e.ctrlKey) {
        if (e.which === 83) { // Ctrl + s
          e.preventDefault()
          this.save_data(1)
        }
        this.is_ctrl_pressed = true
        this.isDragActive = true
        this.reg_canvas.style.cursor = 'pointer'
        this.reg_canvas.removeEventListener('mousedown', this.mouse_down)
        this.reg_canvas.removeEventListener('mouseup', this.mouse_up)
        this.reg_canvas.removeEventListener('mousemove', this.mouse_move)
        this.reg_canvas.removeEventListener('mouseover', this.mouse_over)
      }
    },
    keyup(e){
      if (e.which === 17) {
        this.isDragActive = false
        this.is_ctrl_pressed = false
        this.reg_canvas.style.cursor = 'default'
        this.reg_canvas.addEventListener('mousedown', this.mouse_down)
        this.reg_canvas.addEventListener('mouseup', this.mouse_up)
        this.reg_canvas.addEventListener('mousemove', this.mouse_move)
        this.reg_canvas.addEventListener('mouseover', this.mouse_over)
      }
    },
    reposition() {
      this.reset_zoom_level()
      this.onDragging({top: 0, left: 0})
    },
    onDragging(newRect) {
      // this.$refs.vueDR.parentWidth = 1283
      // // this.$refs.vueDR.parentWidth = 0
      // this.$refs.vueDR.right = 1282
      // this.$refs.vueDR.Height = 0
      // this.$refs.vueDR.bottom = -1
      // console.log('width',this.$refs.vueDR.parentWidth - newRect.left - this.$refs.vueDR.right)
      // console.log('height',this.parentHeight - newRect.top - this.$refs.vueDR.bottom)
      // console.log('newRect',newRect)
      this.$refs.vueDR.top = newRect.top
      this.$refs.vueDR.left = newRect.left
    },
    throttle(fn, gapTime) {
      const _this = this
      return function () {
        const _nowTime = +new Date()
        if (_nowTime - _this._lastTime > gapTime || !_this._lastTime) {
          fn(...arguments)// 函数可以带参数
          _this._lastTime = _nowTime
        }
      }
    },
    handleWheel(e) {
      e.stopPropagation()
      this.throttle(this.pageUpOrDown, 100)(e)
    },
    pageUpOrDown(e) {
      if (e.deltaY > 0) {
        // 向下
        // this.clickNext()//执行的事件逻辑。比如向下翻页
        this.zoom_out()
      } else if (e.deltaY < 0) {
        // 向上
        this.zoom_in()// 比如向上翻页
      }
    },
    getStyle() {
      if (this.isDragActive && this.image_id_list.length !== 0) {
        // console.log("111111111111")
        return {cursor: 'pointer'}
      } else {
        return {}
      }
    },
    getDetectStyle(need_detect) {
      // console.log('2222222222222',need_detect)
      if (need_detect === 0) return {width: '100%', color: 'blue'}
      else return {width: '100%'}
    },
    /*
    初始化
    * */
    get_init() {
      this.invisible_file_input = document.getElementById('invisible_file_input')
      this.img_canvas = document.getElementById('image_canvas')
      this.img_ctx = this.img_canvas.getContext('2d')
      this.reg_canvas = document.getElementById('region_canvas')
      this.leftAll = document.getElementById('leftAll')
      this.leftTree = document.getElementById('leftTree')
      this.tree = document.getElementById('Tree')
      // console.log('leftAll.style.offsetHeight',this.leftAll.offsetHeight)
      // console.log('leftTree.style.offsetHeight',this.leftTree.offsetHeight)
      // console.log('tree.style.offsetHeight',this.tree.offsetHeight)
      this.reg_ctx = this.reg_canvas.getContext('2d')
      this.ui_top_panel = document.getElementById('ui_top_panel')
      this.canvas_panel = document.getElementById('canvas_panel') // 包裹image_canvas和region_canvas的区域
      this.canvas_zoom_level_index = this.CANVAS_DEFAULT_ZOOM_LEVEL_INDEX
      this.current_shape = this.REGION_SHAPE.RECT
    },
    /*
    目录树部分
    * */
    show_node(node, data) {
      console.log('点击')
      console.log('node', node)  //level只是层级 1-3 parent是父节点
      console.log('data', data)
      let current_node_id = node.data.id
      let children_ids = []
      this.find_children_id(data, children_ids)
      this.toggle_all_regions_selection(false)
      for(let j = 0; j<children_ids.length; j++){
        for (let i = 0; i < this.canvas_regions.length; i++) {
          if (this.canvas_regions[i].node_id === children_ids[j]) {
            // console.log('找到对应的区域', this.canvas_regions[i])
            this.set_region_select_state(i, true)
            break
          }
        }
      }
      this.redraw_reg_canvas()
      this.reg_canvas.focus()
    },
    find_children_id(parent_node, children_ids){
      // console.log('parent_node.data.id', parent_node.id)
      children_ids.push(parent_node.id)
      for (let i = 0; i < parent_node.children.length; i++) {
        // console.log('1111')
        // console.log(parent_node.children[i])
        this.find_children_id(parent_node.children[i], children_ids)
      }
    },
    addPush(msg) {
      this.node_data.push(msg)
      this.hasModified = true
      // setTimeout(()=>{
      //   this.$refs.treeRef.scrollTop = this.$refs.treeRef.scrollHeight
      // }, 100)

    },
    /**
     * 目录树右键菜单
     */
    onContextmenu0(event) { // 点击目录树card
      if (this.image_id_list.length === 0) { // 如果没导入图片，则
        return
      }
      this.$contextmenu({
        items: [{
          label: "添加新闻",
          onClick: () => {
            // console.log("添加新闻");
            let num_label = this.count_label_num1(this.node_data, '新闻')
            let new_news = {id: this.nid++, label: '新闻', label_idx: num_label+1, need_detect: 1, xy: [], children: []}
            this.addPush(new_news)
          }
        }, {
          label: "添加报头",
          onClick: () => {
            // console.log("添加报头"); //添加报头和添加普通节点不一样，普通节点可以获取到parent的node信息
            let num_label = this.count_label_num1(this.node_data, '报头')
            let new_newspaperTitle = {id: this.nid++, label: '报头', label_idx: num_label+1, need_detect: 1, xy: [], children: []}
            this.addPush(new_newspaperTitle)
            // this.node_data.push(new_newspaperTitle)  //往目录树添加节点
          }
        }, {
          label: "添加广告",
          onClick: () => {
            // console.log("添加广告");
            let num_label = this.count_label_num1(this.node_data, '广告')
            let new_ads = {id: this.nid++, label: '广告', label_idx: num_label+1, need_detect: 1, xy: [], children: []}
            this.addPush(new_ads)
            // this.node_data.push(new_ads)  //往目录树添加节点
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    onContextmenu(event, node, data) { // 点击目录树node
      if (this.image_id_list.length === 0) { // 如果没导入图片，则
        return
      }
      // console.log(node)
      if (node.data.label === '新闻') {
        // console.log('点击新闻，可以添加标题、作者、时间')
        this.onContextmenu_news(event, node, data)
      } else if (node.data.label === '报头') {
        // console.log('点击报头，可以添加包头部分的东西')
        this.onContextmenu_newspaperTitle(event, node, data)
      } else if (node.data.label === '广告') {
        // console.log('点击广告，可以添加内容和图片')
        this.onContextmenu_ads(event, node, data)
      } else if (node.data.label === '标题' || node.data.label === '分标题') {
        // console.log('点击标题，可以添加副标题、正文')
        this.onContextmenu_title(event, node, data)
      } else {
        // console.log('点击到除了标题和新闻以外的节点，只有删除的选项')
        this.onContextmenu_other(event, node, data)
      }
    },
    onContextmenu_news(event, node, data) {
      this.$contextmenu({
        items: [{
          label: '添加标题',
          onClick: () => {
            // console.log("添加标题");
            this.add_node(node, '标题')
          }
        },{
          label: '添加分标题',
          onClick: () => {
            // console.log("添加标题");
            this.add_node(node, '分标题')
          }
        }, {
          label: '添加作者',
          onClick: () => {
            // console.log("添加作者");
            this.add_node(node, '作者')
          }
        }, {
          label: '添加时间',
          onClick: () => {
            // console.log("添加时间");
            this.add_node(node, '时间')
          }
        }, {
          label: '添加图片',
          onClick: () => {
            // console.log("添加图片");
            this.add_node(node, '图片')
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    onContextmenu_title(event, node, data) {
      let detect_label = '不识别该区域'
      if (node.data.need_detect === 0) {
        detect_label = '识别该区域'
      }
      this.$contextmenu({
        items: [
          {
          label: '添加副标题',
          onClick: () => {
            // console.log("添加副标题");
            this.add_node(node, '副标题')
          }
        },
          {
          label: '添加正文',
          onClick: () => {
            // console.log("添加正文");
            this.add_node(node, '正文')
          }
        }, {
          label: detect_label,
          onClick: () => {
            // console.log(detect_label);
            if (node.data.need_detect === 0) {
              node.data.need_detect = 1 // 不识别该区域
            } else {
              node.data.need_detect = 0 // 不识别该区域
            }
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    onContextmenu_ads(event, node, data) {
      this.$contextmenu({
        items: [{
          label: '添加广告内容',
          onClick: () => {
            // console.log("添加广告内容");
            this.add_node(node, '广告内容')
          }
        }, {
          label: '添加图片',
          onClick: () => {
            // console.log("添加图片");
            this.add_node(node, '图片')
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    onContextmenu_other(event, node, data) {
      let detect_label = '不识别该区域'
      if (node.data.need_detect === 0) {
        detect_label = '识别该区域'
      }
      this.$contextmenu({
        items: [{
          label: detect_label,
          onClick: () => {
            // console.log(detect_label);
            if (node.data.need_detect === 0) {
              node.data.need_detect = 1 // 不识别该区域
            } else {
              node.data.need_detect = 0 // 不识别该区域
            }
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    onContextmenu_newspaperTitle(event, node, data) {
      this.$contextmenu({
        items: [{
          label: '添加报纸名称',
          onClick: () => {
            // console.log("添加报纸名称");
            this.add_node(node, '报纸名称')
          }
        }, {
          label: '添加报纸日期',
          onClick: () => {
            // console.log("添加报纸日期");
            this.add_node(node, '报纸日期')
          }
        }, {
          label: '添加报纸星期',
          onClick: () => {
            // console.log("添加报纸星期");
            this.add_node(node, '报纸星期')
          }
        }, {
          label: '添加报纸版次',
          onClick: () => {
            // console.log("添加报纸版次");
            this.add_node(node, '报纸版次')
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    add_node(node, label) {
      this.current_label = label
      if(label === '图片'){
        this.current_need_detect = 0
      }
      else{
        this.current_need_detect = 1
        // this.current_node = {id: this.nid++, label: label, need_detect: 1, xy: [], children: []}
      }
      this.can_draw_region = true //可以画框
      this.current_parent_node = node
    },
    //删除该节点的目录树信息
    remove_node(node, data) {
      const parent = node.parent
      const children = parent.data.children || parent.data
      const index = children.findIndex(d => d.id === data.id)
      children.splice(index, 1)
      setTimeout(()=>{
        this.order_label_idx(parent, data.label)
      }, 100)
    },
    //删除其该节点以及子节点的区域和目录树信息
    remove_nodes(node, data) {
      this.can_draw_region = false
      this.do_remove_nodes(node, data)
      this.is_all_region_selected = false
      this.is_region_selected = false
      this.user_sel_region_id = -1
      if (this.canvas_regions.length === 0) {
        this.clear_reg_canvas()
      } else {
        this.redraw_reg_canvas()
      }
      this.reg_canvas.focus()
    },
    do_remove_nodes(node, data){
      //删除自身region
      for (let i = 0; i < this.canvas_regions.length; i++) { //删除区域
        if (this.canvas_regions[i].node_id === data.id) {
          this.canvas_regions.splice(i, 1)
          this.img_metadata[this.image_id].regions.splice(i, 1)
          break
        }
      }
      //删除子节点的region和node_data
      for (let i = 0; i < node.childNodes.length; i++) {
        this.do_remove_nodes(node.childNodes[i], node.childNodes[i].data)
      }
      //删除自身node_data信息
      this.remove_node(node, data)
    },
    get_image_id(filename, size) {
      if (typeof (size) === 'undefined') {
        return filename
      } else {
        return filename + size
      }
    },
    set_all_canvas_scale(s) {
      this.img_ctx.scale(s, s) // 只缩放以后的画图操作，会同时缩放坐标
      this.reg_ctx.scale(s, s)
    },
    set_all_canvas_size(w, h) {
      this.img_canvas.height = h
      this.img_canvas.width = w
      this.reg_canvas.height = h
      this.reg_canvas.width = w
      this.canvas_panel.style.height = h + 'px'
      this.canvas_panel.style.width = w + 'px'
    },
    count_label_num1(parent_node_data, label){  //计算一级节点的label数量
      let num = 0
      for(let i=0; i<parent_node_data.length; i++){
        if(parent_node_data[i].label === label){
          num++
        }
      }
      return num
    },
    count_label_num(parent_node_data, label){  //计算二三级节点的label数量
      let num = 0
      for(let i=0; i<parent_node_data.children.length; i++){
        if(parent_node_data.children[i].label === label){
          num++
        }
      }
      return num
    },
    order_label_idx(parent_node, label){
      let idx = 1
      for(let i=0; i<parent_node.childNodes.length; i++){
        if(parent_node.childNodes[i].data.label === label){
          // console.log(idx)
          parent_node.childNodes[i].data.label_idx = idx
          idx++
        }
      }
    },
    // transform regions in image space to canvas space
    load_canvas_regions() {
      // load all existing annotations into canvas_regions
      const regions = this.img_metadata[this.image_id].regions
      // console.log('当前选择的图片id：', this.image_id)
      this.canvas_regions = []
      for (let i = 0; i < regions.length; ++i) {
        const regioni = new ImageRegion()
        regioni.node_id = regions[i].node_id
        for (const key of regions[i].shape_attributes.keys()) { // img_metadata.regions存着该图片各个框的坐标信息
          const value = regions[i].shape_attributes.get(key)
          regioni.shape_attributes.set(key, value)
        }
        this.canvas_regions.push(regioni)
        switch (this.canvas_regions[i].shape_attributes.get('name')) {
          case this.REGION_SHAPE.RECT:
            const x = regions[i].shape_attributes.get('x') / this.canvas_scale // 转化为画布大小
            const y = regions[i].shape_attributes.get('y') / this.canvas_scale
            const width = regions[i].shape_attributes.get('width') / this.canvas_scale
            const height = regions[i].shape_attributes.get('height') / this.canvas_scale
            this.canvas_regions[i].shape_attributes.set('x', Math.round(x))
            this.canvas_regions[i].shape_attributes.set('y', Math.round(y))
            this.canvas_regions[i].shape_attributes.set('width', Math.round(width))
            this.canvas_regions[i].shape_attributes.set('height', Math.round(height))
            break
        }
      }
    },
    redraw_reg_canvas() {
      if (this.current_image_loaded) {
        if (this.canvas_regions.length > 0) {
          // 清空矩形框的画布
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
          if (this.is_region_boundary_visible) { // 画画
            this.draw_all_regions()
          }
        }
      }
    },
    draw_all_regions() {
      for (let i = 0; i < this.canvas_regions.length; ++i) {
        const attr = this.canvas_regions[i].shape_attributes // canvas_regions存的是缩放过的
        const is_selected = this.canvas_regions[i].is_user_selected
        switch (attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            this.draw_rect_region(attr.get('x'),
              attr.get('y'),
              attr.get('width'),
              attr.get('height'),
              is_selected)
            break
        }
      }
    },
    draw_rect_region(x, y, w, h, is_selected) {
      if (is_selected) {
        this.draw_rect(x, y, w, h)
        this.reg_ctx.strokeStyle = this.THEME_SEL_REGION_FILL_BOUNDARY_COLOR
        this.reg_ctx.lineWidth = this.THEME_REGION_BOUNDARY_WIDTH / 2
        this.reg_ctx.stroke() // 绘制出通过 moveTo() 和 lineTo() 方法定义的路径

        this.reg_ctx.fillStyle = this.THEME_SEL_REGION_FILL_COLOR
        this.reg_ctx.globalAlpha = this.THEME_SEL_REGION_OPACITY // 透明度
        this.reg_ctx.fill()
        this.reg_ctx.globalAlpha = 1.0 // 不透明
        // 画边角四个点
        this.draw_control_point(x, y)
        this.draw_control_point(x + w, y + h)
        this.draw_control_point(x, y + h)
        this.draw_control_point(x + w, y)
      } else {
        // draw a fill line
        this.reg_ctx.strokeStyle = this.THEME_BOUNDARY_FILL_COLOR
        this.reg_ctx.lineWidth = this.THEME_REGION_BOUNDARY_WIDTH / 2
        this.draw_rect(x, y, w, h)
        this.reg_ctx.stroke()

        if (w > this.THEME_REGION_BOUNDARY_WIDTH &&
          h > this.THEME_REGION_BOUNDARY_WIDTH) {
          // draw a boundary line on both sides of the fill line
          this.reg_ctx.strokeStyle = this.THEME_BOUNDARY_LINE_COLOR
          this.reg_ctx.lineWidth = this.THEME_REGION_BOUNDARY_WIDTH / 4
          // 花两条线
          this.draw_rect(x - this.THEME_REGION_BOUNDARY_WIDTH / 2,
            y - this.THEME_REGION_BOUNDARY_WIDTH / 2,
            w + this.THEME_REGION_BOUNDARY_WIDTH,
            h + this.THEME_REGION_BOUNDARY_WIDTH)
          this.reg_ctx.stroke()
          this.draw_rect(x + this.THEME_REGION_BOUNDARY_WIDTH / 2,
            y + this.THEME_REGION_BOUNDARY_WIDTH / 2,
            w - this.THEME_REGION_BOUNDARY_WIDTH,
            h - this.THEME_REGION_BOUNDARY_WIDTH)
          this.reg_ctx.stroke()
        }
      }
    },
    // control point for resize of region boundaries
    draw_control_point(cx, cy) {
      this.reg_ctx.beginPath()
      this.reg_ctx.arc(cx, cy, this.REGION_POINT_RADIUS, 0, 2 * Math.PI, false)
      this.reg_ctx.closePath()
      this.reg_ctx.fillStyle = this.THEME_CONTROL_POINT_COLOR
      this.reg_ctx.globalAlpha = 1.0
      this.reg_ctx.fill()
    },
    draw_rect(x, y, w, h) {
      this.reg_ctx.beginPath()
      this.reg_ctx.moveTo(x, y)
      this.reg_ctx.lineTo(x + w, y)
      this.reg_ctx.lineTo(x + w, y + h)
      this.reg_ctx.lineTo(x, y + h)
      this.reg_ctx.closePath()// 闭环,从当前点到开始点的路径
    },
    zoom_in() { // 放大
      if (!this.current_image_loaded) {
        // console.log('请先加载图片,First load some images!')
        return
      }
      if (this.canvas_zoom_level_index === (this.CANVAS_ZOOM_LEVELS.length - 1)) {
        // console.log('Further zoom-in not possible')
      } else {
        this.canvas_zoom_level_index += 1
        this.is_canvas_zoomed = true
        const zoom_scale = this.CANVAS_ZOOM_LEVELS[this.canvas_zoom_level_index]
        this.set_all_canvas_scale(zoom_scale)
        this.set_all_canvas_size(this.canvas_width * zoom_scale,
          this.canvas_height * zoom_scale)
        this.canvas_scale = this.canvas_scale_without_zoom / zoom_scale

        this.load_canvas_regions() // image to canvas space transform
        this.redraw_img_canvas()
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // console.log('Zoomed in to level ' + zoom_scale + 'X')
      }
    },
    zoom_out() { // 缩小
      if (!this.current_image_loaded) {
        // console.log('请先加载图片,First load some images!')
        return
      }
      if (this.canvas_zoom_level_index === 0) { // 不能再缩小了
        // console.log('Further zoom-out not possible')
      } else {
        this.canvas_zoom_level_index -= 1
        this.is_canvas_zoomed = true
        const zoom_scale = this.CANVAS_ZOOM_LEVELS[this.canvas_zoom_level_index]
        this.set_all_canvas_scale(zoom_scale)
        this.set_all_canvas_size(this.canvas_width * zoom_scale,
          this.canvas_height * zoom_scale) // 缩放画布，但是会把图片清空
        this.canvas_scale = this.canvas_scale_without_zoom / zoom_scale

        this.load_canvas_regions() // 加载当前图片的标注框image to canvas space transform
        this.redraw_img_canvas() // 画图片
        this.redraw_reg_canvas() // 画矩形框
        this.reg_canvas.focus()
        // console.log('Zoomed out to level ' + zoom_scale + 'X')
      }
    },
    reset_zoom_level() {
      if (!this.current_image_loaded) {
        // console.log('First load some images!')
        return
      }
      if (this.is_canvas_zoomed) {
        this.is_canvas_zoomed = false
        this.canvas_zoom_level_index = this.CANVAS_DEFAULT_ZOOM_LEVEL_INDEX
        const zoom_scale = this.CANVAS_ZOOM_LEVELS[this.canvas_zoom_level_index]
        this.set_all_canvas_scale(zoom_scale)
        this.set_all_canvas_size(this.canvas_width, this.canvas_height)
        this.canvas_scale = this.canvas_scale_without_zoom

        this.load_canvas_regions() // image to canvas space transform
        this.redraw_img_canvas()
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // console.log('Zoom reset')
      } else {
        // console.log('Cannot reset zoom because image zoom has not been applied!')
      }
    },
    redraw_img_canvas() {
      if (this.current_image_loaded) {
        this.img_ctx.clearRect(0, 0, this.img_canvas.width, this.img_canvas.height)
        this.img_ctx.drawImage(this.current_image, 0, 0,
          this.img_canvas.width, this.img_canvas.height)
      }
    },
    is_on_region_corner(px, py) {
      const region_edge = [-1, -1] // region_id, corner_id [top-left=1,top-right=2,bottom-right=3,bottom-left=4]
      for (let i = 0; i < this.canvas_regions.length; ++i) { // canvas_regions存着当前图片的框坐标，非原图尺度
        const attr = this.canvas_regions[i].shape_attributes
        let result = false
        region_edge[0] = i
        switch (attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            result = this.is_on_rect_edge(attr.get('x'),
              attr.get('y'),
              attr.get('width'),
              attr.get('height'),
              px, py)
            break
        }
        if (result > 0) { // 电机在框i的边缘上
          region_edge[1] = result
          return region_edge
        }
      }
      region_edge[0] = -1
      return region_edge
    },
    is_on_rect_edge(x, y, w, h, px, py) {
      const dx0 = Math.abs(x - px)
      const dy0 = Math.abs(y - py)
      const dx1 = Math.abs(x + w - px)
      const dy1 = Math.abs(y + h - py)

      // [top-left=1,top-right=2,bottom-right=3,bottom-left=4]
      if (dx0 < this.REGION_EDGE_TOL &&
        dy0 < this.REGION_EDGE_TOL) {
        return 1
      }
      if (dx1 < this.REGION_EDGE_TOL &&
        dy0 < this.REGION_EDGE_TOL) {
        return 2
      }
      if (dx1 < this.REGION_EDGE_TOL &&
        dy1 < this.REGION_EDGE_TOL) {
        return 3
      }
      if (dx0 < this.REGION_EDGE_TOL &&
        dy1 < this.REGION_EDGE_TOL) {
        return 4
      }
      return 0
    },
    is_inside_region(px, py, descending_order) {
      const N = this.canvas_regions.length
      if (N === 0) {
        return -1
      }
      let start, end, del
      // traverse the canvas regions in alternating ascending
      // and descending order to solve the issue of nested regions
      if (descending_order) {
        start = N - 1
        end = -1
        del = -1
      } else {
        start = 0
        end = N
        del = 1
      }

      let i = start
      while (i !== end) {
        const yes = this.is_inside_this_region(px, py, i)
        if (yes) {
          return i
        }
        i = i + del
      }
      return -1
    },
    is_inside_this_region(px, py, region_id) {
      const attr = this.canvas_regions[region_id].shape_attributes
      let result = false
      switch (attr.get('name')) {
        case this.REGION_SHAPE.RECT:
          result = this.is_inside_rect(attr.get('x'),
            attr.get('y'),
            attr.get('width'),
            attr.get('height'),
            px, py)
          break
      }
      return result
    },
    is_inside_rect(x, y, w, h, px, py) {
      return px > x &&
        px < (x + w) &&
        py > y &&
        py < (y + h)
    },
    toggle_all_regions_selection(is_selected) {
      for (let i = 0; i < this.canvas_regions.length; ++i) {
        this.canvas_regions[i].is_user_selected = is_selected // 当前图片的所有region都清空
        this.img_metadata[this.image_id].regions[i].is_user_selected = is_selected
      }
      this.is_all_region_selected = is_selected
    },
    rect_update_corner(corner_id, d, x, y) {
      // pre-condition : d[x0,y0,x1,y1] is standarized
      // post-condition : corner is moved ( d may not stay standarized )
      switch (corner_id) {
        case 1: // top-left
          d[0] = x
          d[1] = y
          break
        case 3: // bottom-right
          d[2] = x
          d[3] = y
          break
        case 2: // top-right
          d[2] = x
          d[1] = y
          break
        case 4: // bottom-left
          d[0] = x
          d[3] = y
          break
      }
    },
    rect_standarize_coordinates(d) {
      // d[x0,y0,x1,y1]
      // ensures that (d[0],d[1]) is top-left corner while
      // (d[2],d[3]) is bottom-right corner
      if (d[0] > d[2]) {
        // swap
        const t = d[0]
        d[0] = d[2]
        d[2] = t
      }

      if (d[1] > d[3]) {
        // swap
        const t = d[1]
        d[1] = d[3]
        d[3] = t
      }
    },
    set_region_select_state(region_id, is_selected) {
      this.canvas_regions[region_id].is_user_selected = is_selected
      this.img_metadata[this.image_id].regions[region_id].is_user_selected = is_selected
    },
    /**
     * 在画布上按del键，删除该node以及其children下所有的canvas_regions以及img_matedata中对应regions的信息
     */
    del_sel_regions() {
      if (!this.current_image_loaded) {
        // console.log('请加载图片!', this.current_image_loaded)
        // this.openMessageBox('请加载图片!')
        return
      }
      this.hasModified = true
      let del_region_count = 0
      if (this.is_all_region_selected) {
        del_region_count = this.canvas_regions.length
        this.canvas_regions.splice(0)
        this.img_metadata[this.image_id].regions.splice(0)
      } else {
        const sorted_sel_reg_id = []
        for (let i = 0; i < this.canvas_regions.length; ++i) {
          if (this.canvas_regions[i].is_user_selected) {
            sorted_sel_reg_id.push(i)
          }
        }
        sorted_sel_reg_id.sort(function (a, b) {
          return (b - a)
        })
        for (let i = 0; i < sorted_sel_reg_id.length; ++i) {
          // 由于删除的区域可能是处在第二级的标题或者作者，所以需要删除其节点children下的所有区域
          // remove_node会移除目录树上对应的节点，但是不会移除canvas_regions以及img_matedata中的region
          // 需要有对应的框id才可以删除他们
          const select_node_id = this.img_metadata[this.image_id].regions[sorted_sel_reg_id[i]].node_id
          // console.log('要删除的node_id:', select_node_id)
          const select_node = this.$refs['vuetree'].getNode(select_node_id)// 获取要删除的区域
          // console.log(select_node)
          this.del_node_children_region(select_node) // 在canvas_regions以及img_matedata中删除选中node的叶子结点区域
          // 删除自身在canvas和img_metadata上的节点
          this.canvas_regions.splice(sorted_sel_reg_id[i], 1)// 在canvas_regions中删除自己
          this.img_metadata[this.image_id].regions.splice(sorted_sel_reg_id[i], 1)
          // 删除自身及children在目录树中对应的节点
          this.remove_node(select_node, select_node.data)// 在目录树中删除对应的节点
          del_region_count += 1
        }
      }
      this.is_all_region_selected = false
      this.is_region_selected = false
      this.user_sel_region_id = -1
      if (this.canvas_regions.length === 0) {
        // all regions were deleted, hence clear region canvas
        this.clear_reg_canvas()
      } else {
        this.redraw_reg_canvas()
      }
      this.reg_canvas.focus()
      // console.log('Deleted ' + del_region_count + ' selected regions')
    },
    /**
     * 在画布上按del键，删除该node的children下所有的canvas_regions以及img_matedata中对应regions的信息
     */
    del_node_children_region(node) {
      if (node.childNodes.length === 0) { // 没有子节点
        // console.log('该树没有子节点')
      } else { // 从区域上选择只会删除二级节点
        const children_ids = []
        if (node.level === 2) { // 要删除的是标题
          for (let i = 0; i < node.childNodes.length; i++) {
            children_ids.push(node.childNodes[i].data.id)
          }
          // console.log('选择的是标题，子节点有:', children_ids)
        }
        for (let i = 0; i < children_ids.length; i++) {
          for (let j = 0; j < this.canvas_regions.length; j++) {
            if (this.canvas_regions[j].node_id === children_ids[i]) {
              this.canvas_regions.splice(j, 1) // canvas_region和img_metadata.regions上的东西都一致
              this.img_metadata[this.image_id].regions.splice(j, 1)
              break // 删除下一个children
            }
          }
        }
      }
    },
    clear_reg_canvas() {
      this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
    },
    // 远程文件资源管理器的函数
    getResource() {
      this.isDialogOpen = true
      // console.log(this.$store.state.marking.flag)
      // this.$store.commit('OPEN_DIALOG')
      // this.selectpath = ''
      this.centerDialogVisible = true
      this.explorerInit()
      this.getData(this.selectpath)
    },
    getData(filepath) {
      let i = Date.parse(new Date())
      getFiles(filepath).then((res) => {
        // console.log('返回成功，结果：', res)
        if (res.data.status === 1) {
          this.dataArr = []
          const folderFiles = res.data.allList
          for (const item of folderFiles) {
            // // console.log(item)
            const data_item = {}
            data_item['key'] = i++
            data_item['name'] = item.filename
            data_item['filepath'] = item.filepath
            data_item['type'] = item.type
            if (item.type === 'image') {
              data_item['height'] = item.height
              data_item['size'] = item.size
              data_item['width'] = item.width
              // data_item['base64'] = item.base64
            }
            this.dataArr.push(data_item)
          }
          // console.log('dataArr:', this.dataArr)
          this.currentPath = filepath // 获取filepath下的文件夹后，把当前路径设置为filepath
          this.selectpath = filepath
        } else {
          this.openMessageBox('路径不存在')
          // console.log('11111111', this.dataArr)
        }
      }).catch((error) => {
        // console.log('fileSel与后端通讯发生错误', error)
      })
    },
    clickFolder(item) {
      // console.log('clickFolder', item)
    },
    clickFile(item) {
      // console.log('clickFile', item)
    },
    dblclickFolder(event) {
      // console.log('双击文件夹，进入别的文件夹，需要将当前路径记录在栈里')
      this.pathStack.push(this.currentPath)
      const folderPath = event['filepath']
      // console.log('pathStack:', this.pathStack)
      this.explorerInit()
      if (event['type'] === 'folder') {
        this.getData(folderPath)
      }
    },
    dblclickFile() {
      // console.log('dblclickFile')
    },
    getBack() {
      // console.log('返回上一级')
      const i = this.pathStack.length
      if (i >= 1) {
        this.explorerInit()
        const backPath = this.pathStack[i - 1] // 取栈顶元素
        this.pathStack.pop()
        // console.log('返回上一级路径', backPath)
        this.getData(backPath)
      } else {
        this.openMessageBox('没有上一级了！')
      }
    },
    openMessageBox(message) {
      this.$alert(message, ' ', {
        confirmButtonText: '确定'
        // callback: action => {
        //   this.$message({
        //     type: 'info',
        //     message: `action: ${ action }`
        //   });
        // }
      })
    },
    dragMove(folder, data) {
      // console.log(folder, data)
    },
    explorerInit() {
      this.selectedArr.splice(0, this.selectedArr.length)
      this.dataArr.splice(0, this.dataArr.length)
      this.selection = true
      this.seletedFileList.splice(0, this.seletedFileList.length)
    },

    sumbitData() {
      this.isDialogOpen = false
      // this.$store.commit('CLOSE_DIALOG')
      this.centerDialogVisible = false
      // console.log('sumbit')
      this.seletedFileList.splice(0, this.seletedFileList.length)
      if (this.selectedArr.length !== 0) {
        for (const one of this.selectedArr) {
          this.seletedFileList.push(one)
        }
        // console.log(this.seletedFileList)  //选择的文件列表
      }
      this.store_remote_img_ref()
    },
    // 远程文件加载入图片列表中
    store_remote_img_ref() {
      const user_selected_images = this.seletedFileList // 该任务的文件信息
      const original_image_count = this.img_count // 已经选的文件数量
      // console.log('已经选中的图片数量', this.img_count)
      // console.log('leftAll.style.offsetHeight',this.leftAll.offsetHeight)
      // console.log('leftTree.style.offsetHeight',this.leftTree.offsetHeight)
      // console.log('tree.style.offsetHeight',this.tree.offsetHeight)
      // clear browser cache if user chooses to load new images
      // if (original_image_count === 0) {
      //   localStorage.clear()
      // }

      let discarded_file_count = 0
      for (let i = 0; i < user_selected_images.length; ++i) { // 遍历选好的图片
        const filetype = user_selected_images[i].type // 获得已选中文件的类型
        // // console.log('filetype:', filetype);
        if (filetype === 'image') {
          // console.log('user_selected_images:', user_selected_images[i])
          const img_id = user_selected_images[i].key  //图片数据库的id,每张图片都有唯一的数据库id
          const filename = user_selected_images[i].name
          const filepath = user_selected_images[i].filepath
          const filestatus = user_selected_images[i].status
          const size = user_selected_images[i].size
          // const img_id = this.get_image_id(filename, size) // 如果size没定义，则只用filename作为id
          // // console.log('img_metadata:', this.img_metadata)
          if (this.img_metadata.hasOwnProperty(img_id)) { // 如果img_metadata里面已经存这张图片了
            if (this.img_metadata[img_id].fileref) { // image的详细信息,名字，大小，type等
              // console.log('已经加载过该图片', filename)
            } else {
              this.img_metadata[img_id].fileref = user_selected_images[i]
            }
          } else { // 新建图片
            // console.log('imglist没有这张图片，新建图片信息存入img_metadata')
            this.img_metadata[img_id] = new ImageMetadata(user_selected_images[i], filename, size, img_id, filestatus)
            this.image_id_list.push(img_id)
            let imgDetail = {}
            imgDetail.imageName=filename
            imgDetail.status=filestatus
            this.image_name_list.push(imgDetail)
            this.image_path_list.push(filepath)
            this.img_count += 1 // 已经加载的图片数量++
          }
        } else { // 选择了非图片
          discarded_file_count += 1
        }
      }
      // this.image_name_list.sort(this.compare)
      // this.seletedFileList.sort(this.compare)
      // if (this.img_metadata) {
      //   // console.log('img_metadata', this.img_metadata)
      //   let status_msg = '加载了 ' + (this.img_count - original_image_count) + '张图片.'
      //   if (discarded_file_count) {
      //     status_msg += ' ( 有 ' + discarded_file_count + ' 张非图片文件! )'
      //   }
      //   // console.log(status_msg)
      //   if (this.image_index === -1) { // 还没选择要浏览的图片
      //     this.show_remote_image(0)
      //   } else {
      //     this.show_remote_image(original_image_count) // 显示新加载的第一张图片
      //     // // console.log("zzzzzzzzzzzzzzzzzz",original_image_count)
      //   }
      // } else {
      //   // console.log('未选择任何文件!')
      // }
    },
    show_image(image_index){
      console.log('image_index',image_index)
      console.log('currentIndex',this.currentIndex)
      this.index = image_index
      if(this.currentIndex!= image_index){  //如果点击了别的图片
        if(!this.hasModified)  //没修改过当前图片
        {
          this.show_remote_image(image_index)
        }
        else if(this.submitIndex === this.currentIndex)
        {
          this.show_remote_image(image_index)
        }
        else{
          this.submitDialogVisible = true
        }
      }

    },
    cancel(){
      this.submitDialogVisible = false
      this.show_remote_image(this.index)
    },
    submit(){
      this.submitDialogVisible = false
      this.save_data(0)
      this.show_remote_image(this.index)
    },
    submitstorecenter(){
      this.submitDialogVisible = false
      this.save_data(1)
      this.show_remote_image(this.index)
    },
    show_remote_image(image_index) { // 展示图片 image_index:图片列表的index
      this.reposition()  //复位图片
      this.currentIndex = image_index
      if (this.image_index !== -1) { // 如果是第一次加载，那this.image_index为-1，并且没有保存目录树的必要，因为此时目录树为空
        this.img_metadata[this.image_id].node_tree = this.node_data // 保存目录树
      }
      // console.log('将要展示的图片在列表中的index:', image_index)
      if (this.is_loading_current_image) {
        console.log('请等当前图片加载完再点击')
        return
      }
      const img_id = this.image_id_list[image_index] // 新的image_id
      if (!this.img_metadata.hasOwnProperty(img_id)) {
        console.log('无法找到此图片id:', img_id)
        return
      }
      const img_filename = this.img_metadata[img_id].filename
      const local_node_data = this.img_metadata[img_id].node_tree
      const local_is_vetical = this.img_metadata[img_id].isVetical
      const img_reader = new FileReader()
      this.is_loading_current_image = true // 正在加载图片
      const that = this
      img_reader.addEventListener('loadstart', function (e) {
      }, false)
      img_reader.addEventListener('progress', function (e) {
      }, false)
      img_reader.addEventListener('error', function () {
        that.is_loading_current_image = false
        // console.log('加载图片出错' + img_filename + ' !')
      }, false)
      img_reader.addEventListener('abort', function () {
        that.is_loading_current_image = false
        // console.log('Aborted loading image ' + img_filename + ' !')
      }, false)
      img_reader.addEventListener('load', function () {
        // // console.log('1234345436')
        that.current_image = new Image()
        that.current_image.addEventListener('error', function () {
          that.is_loading_current_image = false
          // console.log('Error loading image ' + img_filename + ' !')
        }, false)
        that.current_image.addEventListener('abort', function () {
          that.is_loading_current_image = false
          // console.log('Aborted loading image ' + img_filename + ' !')
        }, false)
        that.current_image.addEventListener('load', function () {
          // update the current state of application
          that.hasModified = false
          that.image_id = img_id // 当前的图片id
          that.image_index = image_index // 当前的图片在img_list中的索引
          that.current_image_filename = img_filename
          that.current_image_loaded = true // 图片加载成功
          that.is_loading_current_image = false // 目前不在加载图片
          that.click_x0 = 0 // 画框的时候用来记录点
          that.click_y0 = 0
          that.click_x1 = 0
          that.click_y1 = 0
          that.is_user_drawing_region = false
          that.is_window_resized = false
          that.is_user_resizing_region = false
          that.is_user_moving_region = false
          that.is_user_drawing_polygon = false
          that.is_region_selected = false
          that.user_sel_region_id = -1
          that.current_image_width = that.current_image.naturalWidth // 图片真实的宽高
          that.current_image_height = that.current_image.naturalHeight
          // // console.log('that.current_image', that.current_image)
          // console.log('that.current_image_width', that.current_image_width)
          // console.log('that.current_image_height', that.current_image_height)
          // set the size of canvas
          // based on the current dimension of browser window
          const de = document.documentElement
          const canvas_panel_width = de.clientWidth - 230 // 宽度-侧边栏的宽度 页面用于显示图像部分的宽高
          const canvas_panel_height = de.clientHeight - 2 * that.ui_top_panel.offsetHeight// 高度-2倍顶栏
          that.canvas_width = that.current_image_width // 真实图片宽度
          that.canvas_height = that.current_image_height
          if (that.canvas_width > canvas_panel_width) { // 如果原图像的大小>页面用于显示图片区域的大小
            // resize image to match the panel width
            const scale_width = canvas_panel_width / that.current_image.naturalWidth
            that.canvas_width = canvas_panel_width // resize
            that.canvas_height = that.current_image.naturalHeight * scale_width
          }
          if (that.canvas_height > canvas_panel_height) {
            // resize further image if its height is larger than the image panel
            const scale_height = canvas_panel_height / that.canvas_height
            that.canvas_height = canvas_panel_height
            that.canvas_width = that.canvas_width * scale_height
          }
          that.canvas_width = Math.round(that.canvas_width)
          that.canvas_height = Math.round(that.canvas_height)
          that.canvas_scale = that.current_image.naturalWidth / that.canvas_width
          that.canvas_scale_without_zoom = that.canvas_scale // 缩放比例
          that.set_all_canvas_size(that.canvas_width, that.canvas_height) // resize img_region和cav_region

          // we only need to draw the image once in the image_canvas 在image_canvas上画一次原图
          that.img_ctx.clearRect(0, 0, that.canvas_width, that.canvas_height) // 清空一定区域内的像素
          that.img_ctx.drawImage(that.current_image, 0, 0, that.canvas_width, that.canvas_height)

          // 加载目录树，如果本地该图片的目录树不为空，则加载本地
          // 如果本地为空，远程端目录树不为'none'，则加载远程的node_data和is_vetical
          that.max_id = 0 // 每一张图片都有自己的从0开始的id编号，由于可能会删除区域，所以不可能连续，所以要获得最大的id，方便接下来计数
          if (local_node_data.length !== 0) {
            // console.log('加载本地目录树数据')
            that.isVetical = local_is_vetical // 加载本地该图片的isVetical信息
            // console.log('本地的isVetical', that.isVetical)
            that.node_data = local_node_data // 加载本地目录树，由于加载本地，所以本地的region已经存了所有的信息了
            for (let i = 0; i < that.node_data.length; i++) { // 获取该目录树的最大id
              that.get_max_id(that.node_data[i])
            }
          } else {
            if (that.remote_node_data !== 'none') {
              // console.log('加载远程目录树数据')
              that.node_data = that.remote_node_data // 加载远程的目录树信息
              that.isVetical = that.remote_is_vetical // 加载远程端的is_vetical信息
              // 把远程端的目录树信息写入that.img_metadata[img_id].
              that.remote_regions = []
              for (let i = 0; i < that.node_data.length; i++) {
                that.load_remote_data(that.node_data[i]) // 把node_data写入regions
                that.get_max_id(that.node_data[i]) // 获取目录树当前最大id
              }
              that.img_metadata[img_id].node_tree = that.remote_node_data
              that.img_metadata[img_id].isVetical = that.isVetical
              that.img_metadata[img_id].regions = that.remote_regions
            } else {
              // console.log('本地和远程该目录树都为空')
              that.node_data = local_node_data
              that.isVetical = local_is_vetical
            }
          }
          // console.log('当前node_data的最大id', that.max_id)
          that.nid = that.max_id + 1 // 用来计数
          // console.log('img_metadata', that.img_metadata[img_id])
          that.load_canvas_regions() // 将img_meta中的regions加载到canvas层面
          that.redraw_reg_canvas()
          that.reg_canvas.focus() // 焦点设置在regcav上，以便画图
        })
        // // console.log('img_reader.result', img_reader.result)
        that.current_image.src = img_reader.result
      }, false)
      new Promise((resolve, reject) => {
        resolve(getBase64(that.img_metadata[img_id].fileref.filepath, that.img_metadata[img_id].fileid))// 请求img的地址
      }).then((res) => {
        // // console.log(that.img_metadata[img_id].base64_img_data)
        // console.log(res)
        // console.log("marking里的getBase64:")
        // console.log(that.img_metadata[img_id].fileref.filepath)
        // console.log(that.img_metadata[img_id].fileid)
        that.img_metadata[img_id].base64_img_data = res.data.imageBase64
        that.remote_node_data = res.data.node_data // 获取远程的nodedata，如果为'none',则说明远程端没有该文件的标注数据
        that.remote_is_vetical = res.data.is_vetical // 获取远程的is_vetical状态
        if (that.img_metadata[img_id].base64_img_data === '') {
          // load image from file
          img_reader.readAsDataURL(that.img_metadata[img_id].fileref)
        } else {
          // load image from base64 data or URL
          img_reader.readAsText(new Blob([that.img_metadata[img_id].base64_img_data]))
        }
      })
    },
    get_max_id(n_data) { // 获得目录树的最大id值
      if (n_data['id'] > this.max_id) {
        this.max_id = n_data['id']
      }
      for (let i = 0; i < n_data['children'].length; i++) {
        this.get_max_id(n_data['children'][i])
      }
    },
    load_remote_data(n_data) { // 遍历加载regions
      // // console.log('child', n_data['children'])
      if (n_data['xy'].length !== 0) {
        const x = Math.round(n_data['xy'][0]) // 实际坐标
        const y = Math.round(n_data['xy'][1])
        const width = Math.round(n_data['xy'][2] - n_data['xy'][0])
        const height = Math.round(n_data['xy'][3] - n_data['xy'][1])
        const img_region = new ImageRegion()
        img_region.node_id = n_data['id']
        img_region.shape_attributes.set('name', 'rect')
        img_region.shape_attributes.set('x', x)
        img_region.shape_attributes.set('y', y)
        img_region.shape_attributes.set('width', width)
        img_region.shape_attributes.set('height', height)
        this.remote_regions.push(img_region)
      }
      for (let i = 0; i < n_data['children'].length; i++) {
        this.load_remote_data(n_data['children'][i])
      }
    },
    //键盘移动框
    key_move(move_x, move_y){
      const current_region = this.img_metadata[this.image_id].regions[this.user_sel_region_id]// 用户选择的区域
      const image_attr = current_region.shape_attributes // 真实的坐标 x/y/w/h
      const canvas_attr = this.canvas_regions[this.user_sel_region_id].shape_attributes // 在canvas中的坐标
      const current_node_info = this.$refs['vuetree'].getNode(current_region.node_id)// 当前选择区域的目录树node信息
      // console.log('当前区域对应的目录树节点的信息：', current_node_info)
      switch (canvas_attr.get('name')) {
        case this.REGION_SHAPE.RECT:
          const xnew = image_attr.get('x') + Math.round(move_x * this.canvas_scale) // 因为move_x是在缩小的级别上进行的，所以要*缩小的倍数才能得到实际的坐标
          const ynew = image_attr.get('y') + Math.round(move_y * this.canvas_scale)
          image_attr.set('x', xnew)
          image_attr.set('y', ynew)
          const past_xy = current_node_info.data.xy
          current_node_info.data.xy = []// 初始化节点的信息
          current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[0])
          current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[1])
          current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[2])
          current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[3])
          this.hasModified = true
          canvas_attr.set('x', Math.round(image_attr.get('x') / this.canvas_scale))
          canvas_attr.set('y', Math.round(image_attr.get('y') / this.canvas_scale))
      }
      if (this.canvas_regions.length) {
        this.redraw_reg_canvas() // clear old intermediate rectangle
      } else {
        // first region being drawn, just clear the full region canvas
        this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
      }
      switch (canvas_attr.get('name')) {
        case this.REGION_SHAPE.RECT:
          this.draw_rect_region(canvas_attr.get('x'),
            canvas_attr.get('y'),
            canvas_attr.get('width'),
            canvas_attr.get('height'),
            true)
          break
      }
    },
    selectFiles() {
      this.getData(this.selectpath)
      this.pathStack.push(this.currentPath)
    },
    save_data(is_save_temp_data) {
      if(this.image_name_list[this.currentIndex].status == 3){
        this.$message({
          message: '该图片已为待审核状态，不可再操作',
          type: 'warning',
        });
        return
      }else{
        let message = '是否确定上传标注';
        if( is_save_temp_data == 1) message = '是否确定暂存标注？'
        this.$confirm(message, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          if (this.image_index === -1) {
            this.$message({
              message: '请先导入图片',
              type: 'warning',
            });
          } else if (this.node_data.length === 0) {
            this.$message({
              message: '请先标注',
              type: 'warning',
            });
          } else {
            this.submitIndex = this.image_index
            const image_path = this.image_path_list[this.image_index]
            const image_id = this.image_id_list[this.image_index]
            if(is_save_temp_data === 1)  this.image_name_list[this.currentIndex].status = 2 //如果是暂存
            else this.image_name_list[this.currentIndex].status = 3
            // this.image_name_list.sort(this.compare)
            postMarkData1(this.node_data, image_path, image_id, this.isVetical, this.markTaskId, is_save_temp_data).then((response) => {
              this.submitSuccessNotify()
              this.$message({
                message: '操作成功！',
                type: 'success',
              });
            }).catch((error) => {
              this.submitFailureNotify(error)
            })
          }
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '已取消'
          });
        });
      }
    },
    closeDialog() {
      this.centerDialogVisible = false
      this.isDialogOpen = false
      // this.$store.commit('CLOSE_DIALOG')
    },
    submitSuccessNotify() {
      this.$notify({
        title: '上传成功',
        type: 'success',
        duration: 2500
      })
    },
    submitFailureNotify(error) {
      this.$notify({
        title: '上传失败' + error,
        type: 'error',
        duration: 2500
      })
    },
    changeVetical() {
      const img_id = this.image_id_list[this.image_index]
      // console.log('this.isVetical', this.isVetical)
      this.img_metadata[img_id].isVetical = this.isVetical // 修改排版状态
      // console.log(this.img_metadata[img_id])
    },
    // reg_canvas鼠标操作
    mouse_down(e){
      this.click_x0 = e.offsetX //相对于region_canvas的坐标
      this.click_y0 = e.offsetY
      // console.log('鼠标按下:', this.click_x0, this.click_y0)
      this.region_edge = this.is_on_region_corner(this.click_x0, this.click_y0) //点击到框的四角上
      let region_id = this.is_inside_region(this.click_x0, this.click_y0)
      //如果鼠标按到了已经选中的区域，可以移动或者调整区域大小
      //如果按到了没有选中的区域或者本身没有区域被选中，则判定为在画框
      if (this.is_region_selected) {  //是否已经有区域被选中
        // check if user clicked on the region boundary
        if (this.region_edge[1] > 0) {  //点击到了区域边角
          if (!this.is_user_resizing_region) {  //如果在resize区域的状态为false，那么改为true
            // resize region
            if (this.region_edge[0] !== this.user_sel_region_id) {  //如果当前选的区域不是已选中的图像区域，就修改区域id
              this.user_sel_region_id = this.region_edge[0]
            }
            this.is_user_resizing_region = true
            // this.isDragActive = false //resize的时候不能拖动图片
          }
        } else { //没有点击到角落
          let yes = this.is_inside_this_region(this.click_x0, this.click_y0, this.user_sel_region_id)  //点击到区域内部
          if (yes) {  //点击到之前选择的框的内部，把移动状态改为true
            if (!this.is_user_moving_region) {
              this.is_user_moving_region = true
              // this.isDragActive = false //移动区域的时候不能拖动
              this.region_click_x = this.click_x0
              this.region_click_y = this.click_y0
            }
          }
          if (region_id === -1) {//点击到别的区域，判定为在画框
            // unselect all regions
            this.is_region_selected = false
            this.user_sel_region_id = -1
            this.toggle_all_regions_selection(false)
            if (this.can_draw_region) { //如果可以画框
              // mousedown on outside any region
              this.is_user_drawing_region = true
              // this.isDragActive = false
            } else {
              // console.log('没有在目录树上新建节点，不能画框')
            }
          }
        }
      } else {  //如果目前没有区域被选中,则判定为在画框
        if (this.can_draw_region) {
          // console.log('没有区域被选中，判定为正在画框')
          this.is_user_drawing_region = true
          // this.isDragActive = false
        } else {
          // console.log('没有在目录树上新建节点不能画框，由于没有区域被选中，所以可以拖动图片')
        }
      }
      e.preventDefault()
    },
    mouse_up(e){
      this.click_x1 = e.offsetX
      this.click_y1 = e.offsetY
      // console.log('鼠标抬起', this.click_x1, this.click_y1)
      let click_dx = Math.abs(this.click_x1 - this.click_x0)  //移动的距离
      let click_dy = Math.abs(this.click_y1 - this.click_y0)
      // this.isDragActive = true
      // 如果用户正在移动区域
      if (this.is_user_moving_region) {  //如果正在移动区域,即在有区域被选中的情况下，鼠标点击被选中的区域
        this.is_user_moving_region = false  //鼠标抬起，结束移动
        // console.log('移动框结束')
        this.reg_canvas.style.cursor = 'default'

        let move_x = Math.round(this.click_x1 - this.region_click_x)  //区域移动的距离
        let move_y = Math.round(this.click_y1 - this.region_click_y)

        if (Math.abs(move_x) > this.MOUSE_CLICK_TOL || Math.abs(move_y) > this.MOUSE_CLICK_TOL) {  //移动区域
          // console.log('更新移动后框的坐标')
          const current_region = this.img_metadata[this.image_id].regions[this.user_sel_region_id]//用户选择的区域
          let image_attr = current_region.shape_attributes //真实的坐标
          let canvas_attr = this.canvas_regions[this.user_sel_region_id].shape_attributes //在canvas中的坐标
          let current_node_info = this.$refs['vuetree'].getNode(current_region.node_id)//当前选择区域的目录树node信息
          // console.log('当前区域对应的目录树节点的信息：', current_node_info)
          switch (canvas_attr.get('name')) {
            case this.REGION_SHAPE.RECT:
              let xnew = image_attr.get('x') + Math.round(move_x * this.canvas_scale) //因为move_x是在缩小的级别上进行的，所以要*缩小的倍数才能得到实际的坐标
              let ynew = image_attr.get('y') + Math.round(move_y * this.canvas_scale)
              image_attr.set('x', xnew)
              image_attr.set('y', ynew)
              let past_xy = current_node_info.data.xy
              current_node_info.data.xy = []//初始化节点的信息
              current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[0])
              current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[1])
              current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[2])
              current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[3])
              this.hasModified = true
              canvas_attr.set('x', Math.round(image_attr.get('x') / this.canvas_scale))
              canvas_attr.set('y', Math.round(image_attr.get('y') / this.canvas_scale))
              break
          }
        }
        // console.log('更新框信息后重新画框')
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // this.save_current_data_to_browser_cache();
        return
      }

      // 如果用户正在重新调整边框大小
      if (this.is_user_resizing_region) {
        // console.log('结束resize框,更新框的信息')
        // click(x0,y0) to click(x1,y1)
        this.is_user_resizing_region = false
        this.reg_canvas.style.cursor = 'default'
        // update the region
        let region_id = this.region_edge[0]
        const current_region = this.img_metadata[this.image_id].regions[region_id]
        let image_attr = current_region.shape_attributes
        let canvas_attr = this.canvas_regions[region_id].shape_attributes
        let current_node_info = this.$refs['vuetree'].getNode(current_region.node_id)//当前选择区域的目录树node信息
        // console.log('当前区域对应的目录树节点的信息：', current_node_info)
        switch (canvas_attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            let d = [canvas_attr.get('x'), canvas_attr.get('y'), 0, 0]
            d[2] = d[0] + canvas_attr.get('width')  //右下
            d[3] = d[1] + canvas_attr.get('height')

            let mx = this.current_x
            let my = this.current_y
            // let preserve_aspect_ratio = false;

            this.rect_update_corner(this.region_edge[1], d, mx, my) //更新左上右下的点
            this.rect_standarize_coordinates(d) //保证是左上右下

            let w = Math.abs(d[2] - d[0])
            let h = Math.abs(d[3] - d[1])

            image_attr.set('x', Math.round(d[0] * this.canvas_scale))
            image_attr.set('y', Math.round(d[1] * this.canvas_scale))
            image_attr.set('width', Math.round(w * this.canvas_scale))
            image_attr.set('height', Math.round(h * this.canvas_scale))
            current_node_info.data.xy = []  //修改目录树中对应节点的坐标信息
            current_node_info.data.xy.push(Math.round(d[0] * this.canvas_scale))
            current_node_info.data.xy.push(Math.round(d[1] * this.canvas_scale))
            current_node_info.data.xy.push(Math.round(d[2] * this.canvas_scale))
            current_node_info.data.xy.push(Math.round(d[3] * this.canvas_scale))
            this.hasModified = true
            canvas_attr.set('x', Math.round(image_attr.get('x') / this.canvas_scale))
            canvas_attr.set('y', Math.round(image_attr.get('y') / this.canvas_scale))
            canvas_attr.set('width', Math.round(image_attr.get('width') / this.canvas_scale))
            canvas_attr.set('height', Math.round(image_attr.get('height') / this.canvas_scale))
            break
        }
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // this.save_current_data_to_browser_cache();
        return
      }

      // denotes a single click (= mouse down + mouse up)单击一个区域，即选中,记录选中区域的id，并且将对应的isselect标记为true
      if (click_dx < this.MOUSE_CLICK_TOL || click_dy < this.MOUSE_CLICK_TOL) {
        // console.log('鼠标按下移动距离过短，判定为单击')
        let region_id = this.is_inside_region(this.click_x0, this.click_y0)
        if (region_id >= 0) {
          // first click selects region
          // console.log('选中框id：', region_id)
          this.user_sel_region_id = region_id
          this.is_region_selected = true
          this.is_user_moving_region = false
          this.is_user_drawing_region = false
          this.can_draw_region = false
          //将目录树的节点设置为高亮状态
          let select_node_id = this.canvas_regions[region_id].node_id
          // console.log('选中框的region_id：', select_node_id)
          this.$refs['vuetree'].setCurrentKey()
          this.$refs['vuetree'].setCurrentKey(select_node_id)
          // this.selectCamera(select_node_id)
          // de-select all other regions if the user has not pressed Shift
          if (!e.shiftKey) {
            this.toggle_all_regions_selection(false)
          }
          this.set_region_select_state(region_id, true)
          //show_message('Click and drag to move or resize the selected region');
        } else {
          // console.log('没有框被选中,取消所有框的选择状态')
          if (this.is_user_drawing_region) {  //如果没有区域被选中，鼠标按下移动的距离又很小，则全部设置为未选中
            // clear all region selection
            this.is_user_drawing_region = false
            this.is_region_selected = false
            this.use_sel_region_id = -1
            this.$refs['vuetree'].setCurrentKey()
            this.toggle_all_regions_selection(false)
          }
        }
        // console.log('取消画框')
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        return
      }
      // 如果用户画框结束
      if (this.is_user_drawing_region) {
        // console.log('画框结束')
        this.is_user_drawing_region = false
        let num_label = this.count_label_num(this.current_parent_node.data, this.current_label)
        let current_node = {id: this.nid++, label: this.current_label, label_idx: num_label+1, need_detect: this.current_need_detect, xy: [], children: []}
        // this.can_draw_region = false //禁止画框，需要在目录树上新建节点才可以画框
        let region_x0, region_y0, region_x1, region_y1
        // ensure this (x0,y0) is top-left and (x1,y1) is bottom-right
        if (this.click_x0 < this.click_x1) {
          region_x0 = this.click_x0
          region_x1 = this.click_x1
        } else {
          region_x0 = this.click_x1
          region_x1 = this.click_x0
        }
        if (this.click_y0 < this.click_y1) {
          region_y0 = this.click_y0
          region_y1 = this.click_y1
        } else {
          region_y0 = this.click_y1
          region_y1 = this.click_y0
        }

        let original_img_region = new ImageRegion()  //新建一个矩形区域，实际大小
        let canvas_img_region = new ImageRegion()  //画布大小
        let region_dx = Math.abs(region_x1 - region_x0) //区域的大小
        let region_dy = Math.abs(region_y1 - region_y0)

        // newly drawn region is automatically selected
        this.toggle_all_regions_selection(false)
        original_img_region.is_user_selected = true
        canvas_img_region.is_user_selected = true
        original_img_region.node_id = current_node.id //记录node_id
        canvas_img_region.node_id = current_node.id
        this.is_region_selected = true
        this.user_sel_region_id = this.canvas_regions.length // new region's id

        if (region_dx > this.REGION_MIN_DIM || region_dy > this.REGION_MIN_DIM) { // avoid regions with 0 dim
          switch (this.current_shape) {
            case this.REGION_SHAPE.RECT:
              let x = Math.round(region_x0 * this.canvas_scale) //实际坐标
              let y = Math.round(region_y0 * this.canvas_scale)
              let width = Math.round(region_dx * this.canvas_scale)
              let height = Math.round(region_dy * this.canvas_scale)
              original_img_region.shape_attributes.set('name', 'rect')
              original_img_region.shape_attributes.set('x', x)
              original_img_region.shape_attributes.set('y', y)
              original_img_region.shape_attributes.set('width', width)
              original_img_region.shape_attributes.set('height', height)
              current_node['xy'] = []
              current_node['xy'].push(region_x0 * this.canvas_scale)
              current_node['xy'].push(region_y0 * this.canvas_scale)
              current_node['xy'].push(region_x1 * this.canvas_scale)
              current_node['xy'].push(region_y1 * this.canvas_scale)
              canvas_img_region.shape_attributes.set('name', 'rect')
              canvas_img_region.shape_attributes.set('x', Math.round(x / this.canvas_scale))
              canvas_img_region.shape_attributes.set('y', Math.round(y / this.canvas_scale))
              canvas_img_region.shape_attributes.set('width', Math.round(width / this.canvas_scale))
              canvas_img_region.shape_attributes.set('height', Math.round(height / this.canvas_scale))
              // console.log(this.current_node)
              // console.log(this.current_parent_node)
              this.current_parent_node.data.children.push(current_node)  //data绑定了node_data，data发生改变，node_data也发生改变
              this.hasModified = true
              // setTimeout(() => {
              //   this.$refs.treeRef.scrollTop = this.$refs.treeRef.scrollHeight
              // }, 100)
              this.img_metadata[this.image_id].regions.push(original_img_region)
              this.canvas_regions.push(canvas_img_region)
              break
          }
        } else {
          // console.log('不能添加这么小的框!')
        }
        this.redraw_reg_canvas()  //region全部重画
        this.reg_canvas.focus()
        // this.save_current_data_to_browser_cache()
      }
    },
    mouse_move(e){
      if (!this.current_image_loaded) {
        // console.log('还在加载图片')
        return
      }
      this.current_x = e.offsetX
      this.current_y = e.offsetY
      // // console.log('mousemove:', this.current_x, this.current_y)
      if (this.is_region_selected) { //调整鼠标指针
        // // console.log('有区域被选中')
        if (!this.is_user_resizing_region) { //如果不在resize边框
          // check if user moved mouse cursor to region boundary
          // which indicates an intention to resize the reigon

          this.region_edge = this.is_on_region_corner(this.current_x, this.current_y)

          if (this.region_edge[0] === this.user_sel_region_id) {
            // console.log('鼠标移动到被选中的边框角落,鼠标变化为特定的形状')
            switch (this.region_edge[1]) {
              // rect
              case 1: // top-left corner of rect
              case 3: // bottom-right corner of rect
                this.reg_canvas.style.cursor = 'nwse-resize' //1-3方向的箭头
                break
              case 2: // top-right corner of rect
              case 4: // bottom-left corner of rect
                this.reg_canvas.style.cursor = 'nesw-resize'//2-4
                break
              default:
                this.reg_canvas.style.cursor = 'default' //指针
            }
          } else {
            let yes = this.is_inside_this_region(this.current_x,
              this.current_y,
              this.user_sel_region_id)  //如果鼠标移动到选中的区域内部
            if (yes) {
              this.reg_canvas.style.cursor = 'move'
            } else {
              if(this.isDragActive === false)
                this.reg_canvas.style.cursor = 'default'
              else
                this.reg_canvas.style.cursor = 'pointer'
            }
          }
        }
      }

      if (this.is_user_drawing_region) {  //如果正在画框
        // console.log('正在画框')
        // draw region as the user drags the mouse cousor
        if (this.canvas_regions.length) {
          this.redraw_reg_canvas() // 去除中间框，只画已有的框 clear old intermediate rectangle
        } else {
          // first region being drawn, just clear the full region canvas
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
        }

        let region_x0, region_y0  //左上角

        if (this.click_x0 < this.current_x) {
          if (this.click_y0 < this.current_y) {
            region_x0 = this.click_x0
            region_y0 = this.click_y0
          } else {
            region_x0 = this.click_x0
            region_y0 = this.current_y
          }
        } else {
          if (this.click_y0 < this.current_y) {
            region_x0 = this.current_x
            region_y0 = this.click_y0
          } else {
            region_x0 = this.current_x
            region_y0 = this.current_y
          }
        }
        let dx = Math.round(Math.abs(this.current_x - this.click_x0))
        let dy = Math.round(Math.abs(this.current_y - this.click_y0))

        switch (this.current_shape) {
          case this.REGION_SHAPE.RECT:
            this.draw_rect_region(region_x0, region_y0, dx, dy, false)
            break
        }
        this.reg_canvas.focus()
      }

      if (this.is_user_resizing_region) { //如果正在调整边框
        // user has clicked mouse on bounding box edge and is now moving it
        // draw region as the user drags the mouse cousor
        if (this.canvas_regions.length) {
          this.redraw_reg_canvas() // clear old intermediate rectangle
        } else {
          // first region being drawn, just clear the full region canvas
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
        }

        let region_id = this.region_edge[0]
        let attr = this.canvas_regions[region_id].shape_attributes
        switch (attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            // original rectangle
            let d = [attr.get('x'), attr.get('y'), 0, 0]
            d[2] = d[0] + attr.get('width')  //右下坐标
            d[3] = d[1] + attr.get('height')

            let mx = this.current_x  //目前鼠标的位置
            let my = this.current_y
            //this.region_edge[1]正在哪个角resize
            this.rect_update_corner(this.region_edge[1], d, mx, my) //可能会使左上右下坐标顺序发生变化
            this.rect_standarize_coordinates(d)  //防止左上右下坐标顺序发生变化

            let w = Math.abs(d[2] - d[0])
            let h = Math.abs(d[3] - d[1])
            this.draw_rect_region(d[0], d[1], w, h, true)
            break
        }
        this.reg_canvas.focus()
      }

      if (this.is_user_moving_region) {
        // console.log('正在移动区域')
        // draw region as the user drags the mouse cousor
        if (this.canvas_regions.length) {
          this.redraw_reg_canvas() // clear old intermediate rectangle
        } else {
          // first region being drawn, just clear the full region canvas
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
        }
        let move_x = (this.current_x - this.region_click_x)
        let move_y = (this.current_y - this.region_click_y)
        let attr = this.canvas_regions[this.user_sel_region_id].shape_attributes

        switch (attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            this.draw_rect_region(attr.get('x') + move_x,
              attr.get('y') + move_y,
              attr.get('width'),
              attr.get('height'),
              true)
            break
        }
        this.reg_canvas.focus()
      }
    },
    mouse_over(){
      // change the mouse cursor icon
      // // console.log('鼠标重新移入画布，重画region')
      this.redraw_reg_canvas()
      this.reg_canvas.focus()
    },

  }
}

</script>

<style scoped>
body {
  min-width: 800px;
  padding: 0;
  margin: 0;
  font-family: "Microsoft YaHei";
}

body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, button, textarea, p, blockquote, table, th, td {
  margin: 0;
  padding: 0;
}

.top_panel {
  position: fixed;
  display: block;
  font-size: medium;
  background-color: #42b983;
  color: whitesmoke;
  z-index: 10;
  margin: 0;
  padding: 0;
  width: 100%;
}

.navbar {
  display: right;
}

.navbar ul {
  display: inline;
  list-style-type: none;
  overflow: hidden;
}

.navbar li {
  float: left;
}

.navbar li a, .drop_menu_item {
  display: inline-block;
  color: whitesmoke;
  padding: 0.65em 1.2em;
  text-decoration: none;
}

.navbar li a:hover, .dropdown:hover {
  background-color: #42b983;
  cursor: pointer;
}

.navbar li.dropdown {
  display: inline-block;
}

.navbar .dropdown-content {
  display: none;
  position: absolute;
  background-color: #42b983;
  min-width: 120px;
  border: 1px solid #ffffff;
  font-size: small;
}

.navbar .dropdown-content a {
  color: whitesmoke;
  padding: 0.4em 0.6em;
  text-decoration: none;
  display: block;
  text-align: left;
  background-color: #42b983;
  float: none;
}

.navbar .dropdown-content a:hover {
  background-color: #FFC000;
  color: whitesmoke;
}

.navbar .dropdown:hover .dropdown-content {
  display: block;
}

.toolbar {
  display: inline-block;
  color: white;
  vertical-align: top;
}

.toolbar ul {
  display: inline;
  list-style-type: none;
  overflow: hidden;
}

.toolbar li {
  font-size: medium;
  float: left;
  padding: 0.65em 0.3em;
  color: whitesmoke;
}

.toolbar li:hover {
  background-color: #FFC000;
  color: black;
  cursor: pointer;
}

#fileinfo {
  font-size: small;
  padding: 1.2em 0.8em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Middle panel: containing #image_panel, #leftsidebar */
.middle_panel {
  position: relative;
  display: table;
  table-layout: fixed;
  width: 100%;
  z-index: 1;
  padding: 0;
  top: 3.5em;
  /*padding-top: 1.0125em;  ensures the mouse event (x,y) coordinates are integer */
}

#leftsidebar {
  display: table-cell;
  width: 250px;
  z-index: 10;
  vertical-align: top;
}

#display_area {
  display: table-cell;
  width: 100%;
  z-index: 1;
  margin: 0;
  padding-left: 1em;
  vertical-align: top;
}

#canvas_panel {
  position: relative;
  margin: 0;
  padding: 0;
}

#leftsidebar_collapse_panel {
  display: table-cell;
  position: relative;
  width: 10px;
  z-index: 1;
  vertical-align: top;
  font-size: small;
}

#leftsidebar_collapse_button {
  background-color: #42b983;
  width: 10px;
  height: 25px;
  color: whitesmoke;
  padding: 0.2em;
  border-radius: 0px 5px 5px 0px;
  font-size: large;
}

#leftsidebar_collapse_button:hover {
  color: white;
  cursor: pointer;
}

/* Left sidebar accordion */
button.leftsidebar_accordion {
  font-size: large;
  background-color: #f2f2f2;
  cursor: pointer;
  padding: 0.5em 0.5em;
  width: 100%;
  text-align: left;
  border: 0;
  outline: none;
}

button.leftsidebar_accordion:focus {
  outline: none;
}

button.leftsidebar_accordion.active, button.leftsidebar_accordion:hover {
  background-color: #e6e6e6;
}

button.leftsidebar_accordion:after {
  content: '\02795';
  color: #4d4d4d;
  float: right;
}

button.leftsidebar_accordion.active:after {
  content: '\2796';
}

.leftsidebar_accordion_panel {
  display: none;
  padding-top: 0;
  padding-left: 0.5em;
  font-size: small;
  border-right: 2px solid #f2f2f2;
  border-bottom: 2px solid #f2f2f2;
}

.leftsidebar_accordion_panel.show {
  display: block;
}

/* Region shape selection panel inside leftsidebar */
ul.region_shape {
  font-size: xx-large;
  list-style-type: none;
  overflow: hidden;
  padding: 0.4em 0;
  margin: 0;
}

ul.region_shape li {
  float: left;
  padding: 0 0.2em;
  fill: #ffffff;
  stroke: #000000;
}

ul.region_shape li:hover {
  cursor: pointer;
  fill: #ffffff;
  stroke: #ff0000;
}

ul.region_shape .selected {
  fill: #ffffff;
  stroke: #ff0000;
}

/* Loaded image list shown in leftsidebar panel */
#img_list_panel {
  display: none;
  height: 0;
  font-size: small;
  overflow: scroll;
}

#img_list_panel ul {
  position: relative;
  line-height: 1.3em;
  padding-left: 0;
  list-style-type: none;
}

#img_list_panel li {
  white-space: nowrap;
}

#img_list_panel li:hover {
  background-color: #cccccc;
  color: #000000;
  cursor: pointer;
}

#message_panel {
  position: fixed;
  left: 0;
  bottom: 0px;
  line-height: 3em;
  width: 100%;
  background-color: #00a9cf;
  color: black;
  font-size: small;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  z-index: 1000;
}

#invisible_file_input {
  width: 0.1px;
  height: 0.1px;
  opacity: 0;
  overflow: hidden;
  position: absolute;
  z-index: -1;
}

.text_panel {
  display: none;
  margin: auto;
  font-size: medium;
  line-height: 1.3em;
  margin: 0;
  max-width: 700px;
}

.text_panel li {
  margin: 1em 0;
  text-align: left;
}

.text_panel p {
  text-align: left;
}

.action_text_link {
  background-color: #aaeeff;
  color: #000000;
}

.action_text_link:hover {
  cursor: pointer;
}

.svg_button:hover {
  cursor: pointer;
}

.tool_button {
  color: blue;
  cursor: pointer;
}

.tool_button:hover {
  color: red;
}

/* region and file attributes input panel (spreadsheet like) */
#attributes_panel {
  display: none;
  position: fixed;
  bottom: 0;
  z-index: 10;
  width: 100%;
  max-height: 30%;
  overflow: auto;
  background-color: #ffffff;
  border-top: 4px solid #000000;
  padding: 0em 0em;
  padding-bottom: 2em;
  font-size: small;
}

#attributes_panel table {
  border-collapse: collapse;
  table-layout: fixed;
  margin: 1em;
  margin-bottom: 2em;
}

#attributes_panel td {
  border: 1px solid #999999;
  padding: 1em 1em;
  margin: 0;
  height: 1em;
  white-space: nowrap;
  vertical-align: top;
}

#attributes_panel tr:first-child td, #attributes_panel td:first-child {
  padding: 1em 1em;
  text-align: center;
}

#attributes_panel input {
  border: none;
  padding: 0;
  margin: 0;
  display: table-cell;
  height: 1.3em;
  font-size: small;
  background-color: #ffffff;
  vertical-align: top;
}

#attributes_panel input:hover {
  background-color: #e6e6e6;
}

#attributes_panel input:focus {
  background-color: #e6e6e6;
}

#attributes_panel input:not(:focus) {
  text-align: center;
}

#attributes_panel textarea {
  border: none;
  padding: 0;
  margin: 0;
  display: table-cell;
  font-size: small;
  background-color: #ffffff;
}

#attributes_panel textarea:hover {
  background-color: #e6e6e6;
}

#attributes_panel textarea:focus {
  background-color: #e6e6e6;
}

#attributes_panel_toolbar {
  display: block;
  height: 30px;
  width: 100%;
  position: relative;
  padding: 0;
  margin: 0;
}

.attributes_panel_button {
  width: 10px;
  color: black;
  font-size: x-large;
  margin-left: 0.5em;
  padding: 0;
}

.attributes_panel_button:hover {
  color: red;
  cursor: pointer;
}

/* layers of canvas */
#image_panel {
  position: relative;
  display: inline-block;
  margin: auto;
  margin-top: 1em;
}

#image_canvas {
  position: absolute;
  border: 2px solid #d71b1b;
  top: 0px;
  left: 0px;
  z-index: 1;
}

#region_canvas {
  position: absolute;
  top: 0px;
  left: 0px;
  z-index: 2;
}

/* Loading spinbar */
.loading_spinbox {
  display: inline-block;
  border: 0.4em solid #cccccc;
  border-radius: 50%;
  border-top: 0.4em solid #000000;
  -webkit-animation: spin 2s linear infinite;
  animation: spin 2s linear infinite;
}

@-webkit-keyframes spin {
  0% {
    -webkit-transform: rotate(0deg);
  }

  100% {
    -webkit-transform: rotate(360deg);
  }
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.text {
  font-size: 14px;
}

li {
  list-style: none;
}

.item {
  margin-bottom: 18px;
}

.clearfix:before,
.clearfix:after {
  display: table;
  content: "";
}

.clearfix:after {
  clear: both
}

.box-card {
  width: auto;
  /*padding-left: 5px;*/
}

.el-dropdown-link {
  cursor: pointer;
  color: #409EFF;
}

.el-icon-arrow-down {
  font-size: 12px;
}

.demonstration {
  display: block;
  color: #8492a6;
  font-size: 14px;
  margin-bottom: 20px;
}

.custom-class .menu_item__available:hover {
  background: #ffecf2 !important;
  color: #ff4050 !important;
}

.leftSizeBar {
  position: fixed;
}

.box-card {
  height: 100%;
  /*padding: 0;*/
}

.tree_box {
  max-height: 400px;
  overflow: auto;
}

.box {
  max-height: 200px;
  overflow: auto;
}

.explorerBox {
  height: 390px;
  overflow: auto;
}

.el-switch__label {
  position: absolute;
  display: none;
  font-size: 11px !important;
  color: #fff !important;
}

.el-switch__label * {
  font-size: 11px !important;
}

/*打开时文字位置设置*/
.el-switch__label--right {
  z-index: 1;
  right: -10px;
  top: 0.5px;
}

/*关闭时文字位置设置*/
.el-switch__label--left {
  z-index: 1;
  left: 23px;
  top: 0.5px;
}

/*显示文字*/
.el-switch__label.is-active {
  display: block;
}

.el-switch__core {
  width: 45px;
  height: 22px;
  border: 2px solid #DCDFE6;
  border-radius: 13px;
}

.active {
  color: red;
}

.btnClass {
  font-size: 16px;
  margin-right: 30px;
  margin-left: 30px;
}

.mainSizeBar {
  margin-left: 250px;
}

/* >>> .el-tree-node:focus > .el-tree-node__content {
  background-color：rgb(3, 35, 68);
  } */
/* .warpper .el-tree--highlight-current >>> .el-tree-node.is-checked > .el-tree-node__content {
    background-color: rgb(255, 255, 255);
    color:rgb(64, 158, 255);
  }
 .warpper .el-tree--highlight-current >>> .el-tree-node.is-current > .el-tree-node__content {
    background-color: rgb(212, 107, 107);
    color:rgb(3, 35, 68);
  } */
</style>
